/*      */ package com.zimbra.cs.index;
/*      */ 
/*      */ import com.google.common.collect.ImmutableSet;
/*      */ import com.google.common.io.Closeables;
/*      */ import com.zimbra.common.service.ServiceException;
/*      */ import com.zimbra.common.util.Log;
/*      */ import com.zimbra.common.util.ZimbraLog;
/*      */ import com.zimbra.cs.db.Db;
/*      */ import com.zimbra.cs.db.DbPool;
/*      */ import com.zimbra.cs.db.DbPool.DbConnection;
/*      */ import com.zimbra.cs.db.DbSearch;
/*      */ import com.zimbra.cs.db.DbSearch.FetchMode;
/*      */ import com.zimbra.cs.db.DbSearch.Result;
/*      */ import com.zimbra.cs.mailbox.Folder;
/*      */ import com.zimbra.cs.mailbox.MailItem.Type;
/*      */ import com.zimbra.cs.mailbox.MailServiceException;
/*      */ import com.zimbra.cs.mailbox.Mailbox;
/*      */ import com.zimbra.cs.mailbox.MailboxIndex;
/*      */ import com.zimbra.cs.mailbox.Mountpoint;
/*      */ import com.zimbra.cs.mailbox.SearchFolder;
/*      */ import com.zimbra.cs.mailbox.Tag;
/*      */ import com.zimbra.cs.service.util.ItemId;
/*      */ import java.util.ArrayList;
/*      */ import java.util.Collection;
/*      */ import java.util.EnumSet;
/*      */ import java.util.HashMap;
/*      */ import java.util.HashSet;
/*      */ import java.util.Iterator;
/*      */ import java.util.LinkedHashMap;
/*      */ import java.util.LinkedList;
/*      */ import java.util.List;
/*      */ import java.util.Map;
/*      */ import java.util.Map.Entry;
/*      */ import java.util.Set;
/*      */ import org.apache.lucene.document.Document;
/*      */ import org.apache.lucene.index.Term;
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ public class DBQueryOperation
/*      */   extends QueryOperation
/*      */ {
/*      */   private static final int MAX_HITS_PER_CHUNK = 2000;
/*      */   private DbSearchConstraints constraints;
/*      */   private int hitsOffset;
/*      */   private int dbOffset;
/*      */   private int cursorOffset;
/*      */   private boolean allResultsQuery;
/*      */   private boolean includeIsLocalFolders;
/*      */   private boolean includeIsRemoteFolders;
/*      */   private int dbHitCount;
/*      */   private List<DbSearch.Result> dbHits;
/*      */   private List<ZimbraHit> nextHits;
/*      */   private Iterator<DbSearch.Result> dbHitsIter;
/*      */   private boolean atStart;
/*      */   private int hitsPerChunk;
/*      */   private boolean endOfHits;
/*      */   private final Set<MailItem.Type> excludeTypes;
/*      */   private LuceneQueryOperation luceneOp;
/*      */   private LuceneQueryOperation.LuceneResultsChunk luceneChunk;
/*      */   private QueryTarget queryTarget;
/*      */   private final List<QueryInfo> queryInfo;
/*      */   private DbSearch.FetchMode fetch;
/*      */   private QueryExecuteMode executeMode;
/*      */   private final LRUHashMap<ZimbraHit> mSeenHits;
/*      */   
/*      */   private static enum QueryExecuteMode
/*      */   {
/*  108 */     NO_RESULTS, 
/*  109 */     NO_LUCENE, 
/*  110 */     DB_FIRST, 
/*  111 */     LUCENE_FIRST;
/*      */     
/*      */ 
/*      */ 
/*      */     private QueryExecuteMode() {}
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   static List<Folder> getTrashFolders(Mailbox mbox)
/*      */     throws ServiceException
/*      */   {
/*  123 */     return mbox.getFolderById(null, 3).getSubfolderHierarchy();
/*      */   }
/*      */   
/*      */   Set<Folder> getTargetFolders() {
/*  127 */     if ((this.constraints instanceof DbSearchConstraints.Leaf)) {
/*  128 */       DbSearchConstraints.Leaf leaf = (DbSearchConstraints.Leaf)this.constraints;
/*  129 */       return leaf.folders;
/*      */     }
/*  131 */     if ((this.constraints instanceof DbSearchConstraints.Union)) {
/*  132 */       DbSearchConstraints.Union node = (DbSearchConstraints.Union)this.constraints;
/*  133 */       Set<Folder> folders = new HashSet();
/*  134 */       for (DbSearchConstraints subConstraints : node.getChildren()) {
/*  135 */         if ((subConstraints instanceof DbSearchConstraints.Leaf)) {
/*  136 */           folders.addAll(((DbSearchConstraints.Leaf)subConstraints).folders);
/*      */         }
/*      */       }
/*  139 */       return folders;
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*  144 */     return null;
/*      */   }
/*      */   
/*      */   QueryOperation expandLocalRemotePart(Mailbox mbox)
/*      */     throws ServiceException
/*      */   {
/*  150 */     if ((this.constraints instanceof DbSearchConstraints.Leaf)) {
/*  151 */       boolean added = false;
/*      */       
/*  153 */       if (this.includeIsLocalFolders) {
/*  154 */         this.includeIsLocalFolders = false;
/*      */         
/*  156 */         DbSearchConstraints.Leaf leaf = (DbSearchConstraints.Leaf)this.constraints;
/*      */         
/*  158 */         for (Folder f : mbox.getFolderById(null, 11).getSubfolderHierarchy()) {
/*  159 */           if ((!(f instanceof Mountpoint)) && (!(f instanceof SearchFolder)))
/*      */           {
/*  161 */             leaf.folders.add(f);
/*  162 */             added = true;
/*      */           }
/*      */         }
/*  165 */         if (!added) {
/*  166 */           return new NoResultsQueryOperation();
/*      */         }
/*  168 */         return this;
/*      */       }
/*  170 */       if (this.includeIsRemoteFolders) {
/*  171 */         UnionQueryOperation toRet = new UnionQueryOperation();
/*  172 */         this.includeIsRemoteFolders = false;
/*      */         
/*  174 */         for (Folder f : mbox.getFolderById(null, 11).getSubfolderHierarchy()) {
/*  175 */           if ((f instanceof Mountpoint)) {
/*  176 */             Mountpoint mpt = (Mountpoint)f;
/*  177 */             if (!mpt.isLocal())
/*      */             {
/*  179 */               DBQueryOperation db = new DBQueryOperation();
/*  180 */               db.addInRemoteFolder(mpt.getTarget(), "", true, true);
/*  181 */               toRet.add(db);
/*  182 */               added = true;
/*      */             }
/*      */           }
/*      */         }
/*  186 */         if (!added) {
/*  187 */           return new NoResultsQueryOperation();
/*      */         }
/*  189 */         return toRet;
/*      */       }
/*      */       
/*  192 */       return this;
/*      */     }
/*      */     
/*  195 */     throw new IllegalStateException("expandLocalRemotePart must be called before optimize() is called");
/*      */   }
/*      */   
/*      */ 
/*      */   QueryOperation ensureSpamTrashSetting(Mailbox mbox, boolean includeTrash, boolean includeSpam)
/*      */     throws ServiceException
/*      */   {
/*  202 */     if (!hasSpamTrashSetting()) {
/*  203 */       ArrayList<Folder> exclude = new ArrayList();
/*  204 */       if (!includeSpam) {
/*  205 */         Folder spam = mbox.getFolderById(null, 4);
/*  206 */         exclude.add(spam);
/*      */       }
/*      */       Iterator<Folder> iter;
/*  209 */       if (!includeTrash) {
/*  210 */         List<Folder> trashFolders = getTrashFolders(mbox);
/*  211 */         for (iter = trashFolders.iterator(); iter.hasNext();) {
/*  212 */           Folder cur = (Folder)iter.next();
/*  213 */           exclude.add(cur);
/*      */         }
/*      */       }
/*      */       
/*  217 */       this.constraints.ensureSpamTrashSetting(mbox, exclude);
/*      */     }
/*  219 */     return this;
/*      */   }
/*      */   
/*      */   boolean hasSpamTrashSetting()
/*      */   {
/*  224 */     if ((this.luceneOp != null) && (this.luceneOp.hasSpamTrashSetting())) {
/*  225 */       return true;
/*      */     }
/*  227 */     if (this.includeIsRemoteFolders) {
/*  228 */       return true;
/*      */     }
/*  230 */     return this.constraints.hasSpamTrashSetting();
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   void forceHasSpamTrashSetting()
/*      */   {
/*  237 */     this.constraints.forceHasSpamTrashSetting();
/*      */   }
/*      */   
/*      */   boolean hasNoResults()
/*      */   {
/*  242 */     return this.constraints.hasNoResults();
/*      */   }
/*      */   
/*      */   boolean hasAllResults()
/*      */   {
/*  247 */     return this.allResultsQuery;
/*      */   }
/*      */   
/*      */   Set<QueryTarget> getQueryTargets()
/*      */   {
/*  252 */     return ImmutableSet.of(this.queryTarget);
/*      */   }
/*      */   
/*      */   List<QueryInfo> getQueryInfo() {
/*  256 */     return this.queryInfo;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */   DbSearchConstraints.Leaf getTopLeafConstraint()
/*      */   {
/*  264 */     if ((this.constraints instanceof DbSearchConstraints.Intersection)) {
/*  265 */       DbSearchConstraints.Intersection and = (DbSearchConstraints.Intersection)this.constraints;
/*  266 */       return and.getLeafChild(); }
/*  267 */     if ((this.constraints instanceof DbSearchConstraints.Union)) {
/*  268 */       DbSearchConstraints top = new DbSearchConstraints.Intersection();
/*  269 */       this.constraints = top.and(this.constraints);
/*  270 */       return ((DbSearchConstraints.Intersection)this.constraints).getLeafChild();
/*      */     }
/*  272 */     return (DbSearchConstraints.Leaf)this.constraints;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   void setLuceneQueryOperation(LuceneQueryOperation op)
/*      */   {
/*  285 */     this.allResultsQuery = false;
/*  286 */     if (this.luceneOp == null) {
/*  287 */       this.luceneOp = op;
/*      */     } else {
/*  289 */       this.luceneOp.addClause(op.getQueryString(), op.getQuery(), true);
/*      */     }
/*      */   }
/*      */   
/*      */   public void addItemIdClause(Mailbox mbox, ItemId itemId, boolean truth) {
/*  294 */     this.allResultsQuery = false;
/*  295 */     if (itemId.belongsTo(mbox)) {
/*  296 */       assert (this.queryTarget.isCompatibleLocal()) : (getTopLeafConstraint() + "," + itemId);
/*  297 */       this.queryTarget = QueryTarget.LOCAL;
/*  298 */       getTopLeafConstraint().addItemIdClause(Integer.valueOf(itemId.getId()), truth);
/*      */     } else {
/*  300 */       assert (this.queryTarget != QueryTarget.LOCAL) : (getTopLeafConstraint() + "," + itemId);
/*  301 */       this.queryTarget = new QueryTarget(itemId.getAccountId());
/*  302 */       getTopLeafConstraint().addRemoteItemIdClause(itemId, truth);
/*      */     }
/*      */   }
/*      */   
/*      */   public void addDateRange(long min, boolean minInclusive, long max, boolean maxInclusive, boolean bool) {
/*  307 */     this.allResultsQuery = false;
/*  308 */     getTopLeafConstraint().addDateRange(min, minInclusive, max, maxInclusive, bool);
/*      */   }
/*      */   
/*      */   public void addMDateRange(long min, boolean minInclusive, long max, boolean maxInclusive, boolean bool) {
/*  312 */     this.allResultsQuery = false;
/*  313 */     getTopLeafConstraint().addMDateRange(min, minInclusive, max, maxInclusive, bool);
/*      */   }
/*      */   
/*      */   public void addCalStartDateRange(long min, boolean minInclusive, long max, boolean maxInclusive, boolean bool) {
/*  317 */     this.allResultsQuery = false;
/*  318 */     getTopLeafConstraint().addCalStartDateRange(min, minInclusive, max, maxInclusive, bool);
/*      */   }
/*      */   
/*      */   public void addCalEndDateRange(long min, boolean minInclusive, long max, boolean maxInclusive, boolean bool) {
/*  322 */     this.allResultsQuery = false;
/*  323 */     getTopLeafConstraint().addCalEndDateRange(min, minInclusive, max, maxInclusive, bool);
/*      */   }
/*      */   
/*      */   public void addConvCountRange(long min, boolean minInclusive, long max, boolean maxInclusive, boolean bool) {
/*  327 */     this.allResultsQuery = false;
/*  328 */     getTopLeafConstraint().addConvCountRange(min, minInclusive, max, maxInclusive, bool);
/*      */   }
/*      */   
/*      */   public void addModSeqRange(long min, boolean minInclusive, long max, boolean maxInclusive, boolean bool) {
/*  332 */     this.allResultsQuery = false;
/*  333 */     getTopLeafConstraint().addModSeqRange(min, minInclusive, max, maxInclusive, bool);
/*      */   }
/*      */   
/*      */   public void addSizeRange(long min, boolean minInclusive, long max, boolean maxInclusive, boolean bool) {
/*  337 */     this.allResultsQuery = false;
/*  338 */     getTopLeafConstraint().addSizeRange(min, minInclusive, max, maxInclusive, bool);
/*      */   }
/*      */   
/*      */   public void addSubjectRange(String min, boolean minInclusive, String max, boolean maxInclusive, boolean bool) {
/*  342 */     this.allResultsQuery = false;
/*  343 */     getTopLeafConstraint().addSubjectRange(min, minInclusive, max, maxInclusive, bool);
/*      */   }
/*      */   
/*      */   public void addSenderRange(String min, boolean minInclusive, String max, boolean maxIncluisve, boolean bool) {
/*  347 */     this.allResultsQuery = false;
/*  348 */     getTopLeafConstraint().addSenderRange(min, minInclusive, max, maxIncluisve, bool);
/*      */   }
/*      */   
/*      */   public void addConvId(Mailbox mbox, ItemId convId, boolean truth) {
/*  352 */     this.allResultsQuery = false;
/*  353 */     if (convId.belongsTo(mbox)) {
/*  354 */       if (!this.queryTarget.isCompatibleLocal()) {
/*  355 */         throw new IllegalArgumentException("Cannot addConvId w/ local target b/c DBQueryOperation already has a remote target");
/*      */       }
/*      */       
/*  358 */       this.queryTarget = QueryTarget.LOCAL;
/*  359 */       getTopLeafConstraint().addConvId(convId.getId(), truth);
/*      */     } else {
/*  361 */       if ((this.queryTarget != QueryTarget.UNSPECIFIED) && (!this.queryTarget.toString().equals(convId.getAccountId()))) {
/*  362 */         throw new IllegalArgumentException("Cannot addConvId w/ remote target b/c DBQueryOperation already has an incompatible remote target");
/*      */       }
/*      */       
/*  365 */       this.queryTarget = new QueryTarget(convId.getAccountId());
/*  366 */       getTopLeafConstraint().addRemoteConvId(convId, truth);
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public void addIsLocalClause()
/*      */   {
/*  374 */     if (!this.queryTarget.isCompatibleLocal()) {
/*  375 */       throw new IllegalArgumentException("Cannot addIsLocalFolderClause b/c DBQueryOperation already has a remote target");
/*      */     }
/*  377 */     this.queryTarget = QueryTarget.LOCAL;
/*  378 */     this.allResultsQuery = false;
/*  379 */     this.includeIsLocalFolders = true;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public void addIsRemoteClause()
/*      */   {
/*  386 */     if (this.queryTarget == QueryTarget.LOCAL) {
/*  387 */       throw new IllegalArgumentException("Cannot addIsRemoteFolderClause b/c DBQueryOperation already has a local target");
/*      */     }
/*      */     
/*  390 */     if ((this.queryTarget != QueryTarget.REMOTE) && (this.queryTarget != QueryTarget.UNSPECIFIED)) {
/*  391 */       throw new IllegalArgumentException("Cannot addIsRemoteFolderClause b/c DBQueryOperation already has a remote target: " + this.queryTarget);
/*      */     }
/*      */     
/*  394 */     this.queryTarget = QueryTarget.REMOTE;
/*  395 */     this.allResultsQuery = false;
/*  396 */     this.includeIsRemoteFolders = true;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public void addInRemoteFolder(ItemId remoteFolderId, String subfolderPath, boolean includeSubfolders, boolean bool)
/*      */   {
/*  405 */     this.allResultsQuery = false;
/*  406 */     if ((this.queryTarget != QueryTarget.UNSPECIFIED) && (!this.queryTarget.toString().equals(remoteFolderId.getAccountId()))) {
/*  407 */       throw new IllegalArgumentException("Cannot addInClause b/c DBQueryOperation already has an incompatible remote target");
/*      */     }
/*      */     
/*  410 */     this.queryTarget = new QueryTarget(remoteFolderId.getAccountId());
/*  411 */     getTopLeafConstraint().addInRemoteFolder(remoteFolderId, subfolderPath, includeSubfolders, bool);
/*      */   }
/*      */   
/*      */   public void addInFolder(Folder folder, boolean bool) {
/*  415 */     assert ((!(folder instanceof Mountpoint)) || (((Mountpoint)folder).isLocal())) : folder;
/*      */     
/*  417 */     this.allResultsQuery = false;
/*  418 */     if (bool)
/*      */     {
/*      */ 
/*  421 */       if (!this.queryTarget.isCompatibleLocal()) {
/*  422 */         throw new IllegalArgumentException("Cannot addInClause w/ local target b/c DBQueryOperation already has a remote target");
/*      */       }
/*      */       
/*  425 */       this.queryTarget = QueryTarget.LOCAL;
/*      */     }
/*  427 */     getTopLeafConstraint().addInFolder(folder, bool);
/*      */   }
/*      */   
/*      */   public void addAnyFolder(boolean bool) {
/*  431 */     getTopLeafConstraint().addAnyFolder(bool);
/*  432 */     if (!bool) {
/*  433 */       this.allResultsQuery = false;
/*      */     }
/*      */   }
/*      */   
/*      */   public void addTag(Tag tag, boolean bool) {
/*  438 */     this.allResultsQuery = false;
/*  439 */     getTopLeafConstraint().addTag(tag, bool);
/*      */   }
/*      */   
/*      */   public void close()
/*      */   {
/*  444 */     Closeables.closeQuietly(this.luceneOp);
/*      */   }
/*      */   
/*      */   public void resetIterator()
/*      */   {
/*  449 */     if (this.luceneOp != null) {
/*  450 */       this.luceneOp.resetDocNum();
/*      */     }
/*  452 */     this.nextHits.clear();
/*  453 */     this.mSeenHits.clear();
/*  454 */     if (!this.atStart) {
/*  455 */       this.dbOffset = 0;
/*  456 */       this.dbHitsIter = null;
/*  457 */       this.hitsOffset = 0;
/*  458 */       this.endOfHits = false;
/*  459 */       this.atStart = true;
/*      */     }
/*  461 */     else if (this.dbHits != null) {
/*  462 */       this.dbHitsIter = this.dbHits.iterator();
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public ZimbraHit peekNext()
/*      */     throws ServiceException
/*      */   {
/*  477 */     ZimbraHit toRet = null;
/*  478 */     if (this.nextHits.size() > 0)
/*      */     {
/*  480 */       toRet = (ZimbraHit)this.nextHits.get(0);
/*      */     }
/*      */     else {
/*  483 */       while (toRet == null)
/*      */       {
/*  485 */         if (((this.dbHitsIter == null) || (!this.dbHitsIter.hasNext())) && (!this.endOfHits)) {
/*  486 */           if (this.fetch == null) {
/*  487 */             switch (this.context.getResults().getFetchMode()) {
/*      */             case NORMAL: 
/*  489 */               this.fetch = (isTopLevelQueryOp() ? DbSearch.FetchMode.MAIL_ITEM : DbSearch.FetchMode.ID);
/*  490 */               break;
/*      */             case IMAP: 
/*  492 */               this.fetch = DbSearch.FetchMode.IMAP_MSG;
/*  493 */               break;
/*      */             case IDS: 
/*  495 */               this.fetch = DbSearch.FetchMode.ID;
/*  496 */               break;
/*      */             case MODSEQ: 
/*  498 */               this.fetch = DbSearch.FetchMode.MODSEQ;
/*  499 */               break;
/*      */             case PARENT: 
/*  501 */               this.fetch = DbSearch.FetchMode.PARENT;
/*  502 */               break;
/*      */             default: 
/*  504 */               if (!$assertionsDisabled) throw new AssertionError(this.context.getResults().getFetchMode());
/*      */               break;
/*      */             }
/*      */           }
/*  508 */           if (this.executeMode == null) {
/*  509 */             if (hasNoResults()) {
/*  510 */               this.executeMode = QueryExecuteMode.NO_RESULTS;
/*  511 */             } else if (this.luceneOp == null) {
/*  512 */               this.executeMode = QueryExecuteMode.NO_LUCENE;
/*  513 */             } else if (shouldExecuteDbFirst()) {
/*  514 */               this.luceneOp.clearFilterClause();
/*  515 */               this.executeMode = QueryExecuteMode.DB_FIRST;
/*      */             } else {
/*  517 */               this.executeMode = QueryExecuteMode.LUCENE_FIRST;
/*      */             }
/*      */           }
/*      */           
/*  521 */           getNextChunk();
/*      */         }
/*      */         
/*      */ 
/*  525 */         if ((this.dbHitsIter != null) && (this.dbHitsIter.hasNext())) {
/*  526 */           DbSearch.Result sr = (DbSearch.Result)this.dbHitsIter.next();
/*      */           
/*      */ 
/*      */ 
/*      */ 
/*  531 */           Collection<Document> docs = this.luceneChunk != null ? this.luceneChunk.getHit(sr.getIndexId()) : null;
/*      */           
/*  533 */           if ((docs == null) || (!ZimbraQueryResultsImpl.shouldAddDuplicateHits(sr.getType()))) {
/*  534 */             ZimbraHit toAdd = this.context.getResults().getZimbraHit(this.context.getMailbox(), sr, null, this.fetch);
/*  535 */             if (toAdd != null)
/*      */             {
/*  537 */               if (!this.mSeenHits.containsKey(toAdd)) {
/*  538 */                 this.mSeenHits.put(toAdd, toAdd);
/*  539 */                 this.nextHits.add(toAdd);
/*      */               }
/*      */             }
/*      */           } else {
/*  543 */             for (Document doc : docs) {
/*  544 */               ZimbraHit toAdd = this.context.getResults().getZimbraHit(this.context.getMailbox(), sr, doc, this.fetch);
/*  545 */               if (toAdd != null)
/*      */               {
/*  547 */                 if (!this.mSeenHits.containsKey(toAdd)) {
/*  548 */                   this.mSeenHits.put(toAdd, toAdd);
/*  549 */                   this.nextHits.add(toAdd);
/*      */                 }
/*      */               }
/*      */             }
/*      */           }
/*      */           
/*  555 */           if (this.nextHits.size() > 0) {
/*  556 */             toRet = (ZimbraHit)this.nextHits.get(0);
/*      */           }
/*      */         } else {
/*  559 */           return null;
/*      */         }
/*      */       }
/*      */     }
/*      */     
/*  564 */     return toRet;
/*      */   }
/*      */   
/*      */   public DBQueryOperation()
/*      */   {
/*   61 */     this.constraints = new DbSearchConstraints.Leaf();
/*   62 */     this.hitsOffset = 0;
/*   63 */     this.dbOffset = 0;
/*   64 */     this.cursorOffset = -1;
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*   70 */     this.allResultsQuery = true;
/*   71 */     this.includeIsLocalFolders = false;
/*   72 */     this.includeIsRemoteFolders = false;
/*      */     
/*   74 */     this.dbHitCount = -1;
/*      */     
/*   76 */     this.nextHits = new ArrayList();
/*      */     
/*   78 */     this.atStart = true;
/*   79 */     this.hitsPerChunk = 100;
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*   84 */     this.endOfHits = false;
/*   85 */     this.excludeTypes = EnumSet.noneOf(MailItem.Type.class);
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*   90 */     this.luceneOp = null;
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*   95 */     this.luceneChunk = null;
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*  101 */     this.queryTarget = QueryTarget.UNSPECIFIED;
/*  102 */     this.queryInfo = new ArrayList();
/*      */     
/*  104 */     this.fetch = null;
/*  105 */     this.executeMode = null;
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*  577 */     this.mSeenHits = new LRUHashMap(2048, 100);
/*      */   }
/*      */   
/*      */   static final class LRUHashMap<T> extends LinkedHashMap<T, T> {
/*      */     private static final long serialVersionUID = -8616556084756995676L;
/*      */     private final int mMaxSize;
/*      */     
/*  584 */     LRUHashMap(int maxSize) { super(0.75F, true);
/*  585 */       this.mMaxSize = maxSize;
/*      */     }
/*      */     
/*      */     LRUHashMap(int maxSize, int tableSize) {
/*  589 */       super(0.75F, true);
/*  590 */       this.mMaxSize = maxSize;
/*      */     }
/*      */     
/*      */     protected boolean removeEldestEntry(Map.Entry<T, T> eldest)
/*      */     {
/*  595 */       return size() > this.mMaxSize;
/*      */     }
/*      */   }
/*      */   
/*      */   public ZimbraHit getNext() throws ServiceException
/*      */   {
/*  601 */     this.atStart = false;
/*  602 */     if (this.nextHits.size() == 0) {
/*  603 */       peekNext();
/*      */     }
/*  605 */     if (this.nextHits.size() == 0) {
/*  606 */       return null;
/*      */     }
/*  608 */     ZimbraHit toRet = (ZimbraHit)this.nextHits.remove(0);
/*  609 */     return toRet;
/*      */   }
/*      */   
/*      */   private Set<MailItem.Type> toDbQueryTypes(Set<MailItem.Type> types) {
/*  613 */     Set<MailItem.Type> result = EnumSet.noneOf(MailItem.Type.class);
/*      */     
/*  615 */     for (MailItem.Type type : types) {
/*  616 */       switch (type) {
/*      */       case FOLDER: 
/*      */       case SEARCHFOLDER: 
/*      */       case TAG: 
/*  620 */         result.add(MailItem.Type.UNKNOWN);
/*  621 */         break;
/*      */       case CONVERSATION: 
/*  623 */         result.add(MailItem.Type.MESSAGE);
/*  624 */         result.add(MailItem.Type.CHAT);
/*  625 */         break;
/*      */       case MESSAGE: 
/*  627 */         result.add(MailItem.Type.MESSAGE);
/*  628 */         result.add(MailItem.Type.CHAT);
/*  629 */         break;
/*      */       case CONTACT: 
/*  631 */         result.add(MailItem.Type.CONTACT);
/*  632 */         break;
/*      */       case APPOINTMENT: 
/*  634 */         result.add(MailItem.Type.APPOINTMENT);
/*  635 */         break;
/*      */       case TASK: 
/*  637 */         result.add(MailItem.Type.TASK);
/*  638 */         break;
/*      */       case DOCUMENT: 
/*  640 */         result.add(MailItem.Type.DOCUMENT);
/*  641 */         break;
/*      */       case NOTE: 
/*  643 */         result.add(MailItem.Type.NOTE);
/*  644 */         break;
/*      */       case FLAG: 
/*  646 */         result.add(MailItem.Type.FLAG);
/*  647 */         break;
/*      */       case WIKI: 
/*  649 */         result.add(MailItem.Type.WIKI);
/*      */       }
/*      */       
/*      */     }
/*      */     
/*  654 */     return result;
/*      */   }
/*      */   
/*      */   private SortBy getSortOrder() {
/*  658 */     return this.context.getResults().getSortBy();
/*      */   }
/*      */   
/*      */   private void dbSearch(List<DbSearch.Result> results, SortBy sort, int offset, int size) throws ServiceException {
/*  662 */     long start = System.currentTimeMillis();
/*  663 */     results.addAll(this.context.getMailbox().index.search(this.constraints, this.fetch, sort, offset, size, this.context.getParams().inDumpster()));
/*      */     
/*  665 */     ZimbraLog.search.debug("DBSearch elapsed=%d", new Object[] { Long.valueOf(System.currentTimeMillis() - start) });
/*      */   }
/*      */   
/*      */   private boolean shouldExecuteDbFirst() throws ServiceException
/*      */   {
/*  670 */     DbSearchConstraints.Leaf top = getTopLeafConstraint();
/*  671 */     if ((top.convId > 0) || (!top.itemIds.isEmpty())) {
/*  672 */       return true;
/*      */     }
/*      */     
/*  675 */     if ((this.luceneOp != null) && (this.luceneOp.shouldExecuteDbFirst())) {
/*  676 */       return true;
/*      */     }
/*      */     
/*  679 */     return this.constraints.tryDbFirst(this.context.getMailbox());
/*      */   }
/*      */   
/*      */   private void noLuceneGetNextChunk(SortBy sort) throws ServiceException {
/*  683 */     dbSearch(this.dbHits, sort, this.hitsOffset, this.hitsPerChunk);
/*      */     
/*  685 */     if (this.dbHits.size() < this.hitsPerChunk) {
/*  686 */       this.endOfHits = true;
/*      */     }
/*      */     
/*  689 */     this.hitsPerChunk *= 2;
/*  690 */     if (this.hitsPerChunk > 2000) {
/*  691 */       this.hitsPerChunk = 2000;
/*      */     }
/*      */   }
/*      */   
/*      */   private void dbFirstGetNextChunk(SortBy sort) throws ServiceException
/*      */   {
/*  697 */     DbSearchConstraints.Leaf sc = getTopLeafConstraint();
/*  698 */     sc.hasIndexId = Boolean.TRUE;
/*      */     
/*      */     do
/*      */     {
/*  702 */       List<DbSearch.Result> dbResults = new ArrayList();
/*  703 */       dbSearch(dbResults, sort, this.dbOffset, 2000);
/*      */       
/*  705 */       if (dbResults.size() < 2000) {
/*  706 */         this.endOfHits = true;
/*      */       }
/*      */       
/*  709 */       if (dbResults.size() > 0) {
/*  710 */         this.dbOffset += dbResults.size();
/*      */         
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */         try
/*      */         {
/*  718 */           Map<Integer, List<DbSearch.Result>> mailItemToResultsMap = new HashMap();
/*      */           
/*  720 */           for (DbSearch.Result sr : dbResults) {
/*  721 */             List<DbSearch.Result> results = (List)mailItemToResultsMap.get(Integer.valueOf(sr.getIndexId()));
/*  722 */             if (results == null) {
/*  723 */               results = new LinkedList();
/*  724 */               mailItemToResultsMap.put(Integer.valueOf(sr.getIndexId()), results);
/*      */             }
/*  726 */             results.add(sr);
/*      */             
/*  728 */             this.luceneOp.addFilterClause(new Term("l.mbox_blob_id", String.valueOf(sr.getIndexId())));
/*      */           }
/*      */           
/*      */ 
/*  732 */           boolean hasMore = true;
/*      */           
/*      */           Iterator i$;
/*      */           
/*  736 */           while (hasMore) {
/*  737 */             this.luceneChunk = this.luceneOp.getNextResultsChunk(6000);
/*  738 */             Set<Integer> indexIds = this.luceneChunk.getIndexIds();
/*  739 */             if (indexIds.size() < 6000) {
/*  740 */               hasMore = false;
/*      */             }
/*  742 */             for (i$ = indexIds.iterator(); i$.hasNext();) { int indexId = ((Integer)i$.next()).intValue();
/*  743 */               List<DbSearch.Result> results = (List)mailItemToResultsMap.get(Integer.valueOf(indexId));
/*  744 */               if (results != null) {
/*  745 */                 for (DbSearch.Result sr : results) {
/*  746 */                   this.dbHits.add(sr);
/*      */                 }
/*      */               } else {
/*  749 */                 ZimbraLog.search.warn("Lucene returned item ID %d but wasn't in resultMap", new Object[] { Integer.valueOf(indexId) });
/*  750 */                 throw ServiceException.FAILURE("Inconsistent DB/Index query results: Text Index returned item ID " + indexId + " but wasn't in resultMap", null);
/*      */               }
/*      */             }
/*      */           }
/*      */         }
/*      */         finally
/*      */         {
/*  757 */           this.luceneOp.clearFilterClause();
/*      */         }
/*      */         
/*      */       }
/*  761 */     } while ((this.dbHits.size() == 0) && (!this.endOfHits));
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   private void luceneFirstGetNextChunk(SortBy sort)
/*      */     throws ServiceException
/*      */   {
/*      */     do
/*      */     {
/*  771 */       this.luceneChunk = this.luceneOp.getNextResultsChunk(Math.min(Db.getINClauseBatchSize(), this.hitsPerChunk));
/*      */       
/*  773 */       DbSearchConstraints.Leaf sc = getTopLeafConstraint();
/*  774 */       sc.indexIds.clear();
/*  775 */       sc.indexIds.addAll(this.luceneChunk.getIndexIds());
/*      */       
/*      */ 
/*  778 */       this.hitsPerChunk *= 2;
/*  779 */       if (this.hitsPerChunk > 2000) {
/*  780 */         this.hitsPerChunk = 2000;
/*      */       }
/*      */       
/*  783 */       if (sc.indexIds.size() == 0)
/*      */       {
/*      */ 
/*  786 */         this.endOfHits = true;
/*      */       }
/*      */       else {
/*  789 */         dbSearch(this.dbHits, sort, -1, -1);
/*      */       }
/*  791 */     } while ((this.dbHits.size() == 0) && (!this.endOfHits));
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   private void getNextChunk()
/*      */     throws ServiceException
/*      */   {
/*  814 */     assert (!this.endOfHits);
/*  815 */     assert ((this.dbHitsIter == null) || (!this.dbHitsIter.hasNext()));
/*      */     
/*  817 */     if (this.executeMode == QueryExecuteMode.NO_RESULTS) {
/*  818 */       ZimbraLog.search.debug("Returned **NO DB RESULTS (no-results-query-optimization)**");
/*  819 */       this.dbHitsIter = null;
/*  820 */       this.endOfHits = true;
/*      */     } else {
/*  822 */       SortBy sort = getSortOrder();
/*  823 */       this.dbHits = new ArrayList();
/*  824 */       switch (this.executeMode) {
/*      */       case NO_RESULTS: 
/*  826 */         if (!$assertionsDisabled) throw new AssertionError();
/*      */         break;
/*      */       case NO_LUCENE: 
/*  829 */         noLuceneGetNextChunk(sort);
/*  830 */         break;
/*      */       case DB_FIRST: 
/*  832 */         dbFirstGetNextChunk(sort);
/*  833 */         break;
/*      */       case LUCENE_FIRST: 
/*  835 */         luceneFirstGetNextChunk(sort);
/*      */       }
/*      */       
/*      */       
/*  839 */       if (this.dbHits.size() == 0) {
/*  840 */         this.dbHitsIter = null;
/*  841 */         this.dbHits = null;
/*  842 */         this.endOfHits = true;
/*      */       } else {
/*  844 */         this.hitsOffset += this.dbHits.size();
/*  845 */         this.dbHitsIter = this.dbHits.iterator();
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */   protected void begin(QueryOperation.QueryContext ctx)
/*      */     throws ServiceException
/*      */   {
/*  853 */     assert (this.context == null);
/*  854 */     this.context = ctx;
/*      */     
/*  856 */     this.hitsPerChunk = ctx.getChunkSize();
/*  857 */     if (this.hitsPerChunk > 2000) {
/*  858 */       this.hitsPerChunk = 2000;
/*      */     }
/*      */     
/*  861 */     this.constraints.setTypes(toDbQueryTypes(this.context.getResults().getTypes()));
/*  862 */     addCursorConstraint();
/*  863 */     addCalItemExpandRange();
/*      */     
/*  865 */     if (this.luceneOp != null) {
/*  866 */       this.hitsPerChunk *= 2;
/*  867 */       this.luceneOp.setDBOperation(this);
/*      */       
/*  869 */       this.luceneOp.begin(new QueryOperation.QueryContext(ctx.getMailbox(), ctx.getResults(), ctx.getParams(), this.hitsPerChunk));
/*      */     }
/*      */   }
/*      */   
/*      */   private void addCalItemExpandRange() {
/*  874 */     SearchParams params = this.context.getParams();
/*  875 */     if (params.getCalItemExpandStart() > 0L) {
/*  876 */       addCalEndDateRange(params.getCalItemExpandStart(), true, -1L, false, true);
/*      */     }
/*  878 */     if (params.getCalItemExpandEnd() > 0L) {
/*  879 */       addCalStartDateRange(-1L, false, params.getCalItemExpandEnd(), true, true);
/*      */     }
/*      */   }
/*      */   
/*      */   private void addCursorConstraint() throws ServiceException {
/*  884 */     SearchParams.Cursor cursor = this.context.getParams().getCursor();
/*  885 */     if (cursor == null) {
/*  886 */       return;
/*      */     }
/*      */     
/*  889 */     if (this.context.getParams().getTypes().contains(MailItem.Type.CONVERSATION)) {
/*  890 */       return;
/*      */     }
/*  892 */     boolean calcOffset = cursor.isIncludeOffset();
/*  893 */     DbSearchConstraints.Leaf offsetConstraints = null;
/*  894 */     SortBy sort = this.context.getParams().getSortBy();
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*  902 */     switch (sort) {
/*      */     case NONE: 
/*  904 */       throw new IllegalArgumentException("Invalid request: cannot use cursor with SortBy=NONE");
/*      */     case TASK_DUE_ASC: 
/*      */     case TASK_DUE_DESC: 
/*      */     case TASK_PERCENT_COMPLETE_ASC: 
/*      */     case TASK_PERCENT_COMPLETE_DESC: 
/*      */     case TASK_STATUS_ASC: 
/*      */     case TASK_STATUS_DESC: 
/*      */     case NAME_LOCALIZED_ASC: 
/*      */     case NAME_LOCALIZED_DESC: 
/*  913 */       return;
/*      */     case DATE_ASC: 
/*  915 */       long low = Long.parseLong(cursor.getSortValue());
/*  916 */       long high = cursor.getEndSortValue() != null ? Long.parseLong(cursor.getEndSortValue()) : -1L;
/*  917 */       DbSearchConstraints.Leaf top = getTopLeafConstraint();
/*  918 */       if (calcOffset) {
/*  919 */         offsetConstraints = top.clone();
/*  920 */         offsetConstraints.addDateRange(-1L, false, low, false, true);
/*      */       }
/*  922 */       top.addDateRange(low, true, high, false, true);
/*  923 */       break;
/*      */     
/*      */     case DATE_DESC: 
/*  926 */       long high = Long.parseLong(cursor.getSortValue());
/*  927 */       long low = cursor.getEndSortValue() != null ? Long.parseLong(cursor.getEndSortValue()) : -1L;
/*  928 */       DbSearchConstraints.Leaf top = getTopLeafConstraint();
/*  929 */       if (calcOffset) {
/*  930 */         offsetConstraints = top.clone();
/*  931 */         offsetConstraints.addDateRange(high, false, -1L, false, true);
/*      */       }
/*  933 */       top.addDateRange(low, false, high, true, true);
/*  934 */       break;
/*      */     
/*      */     case SIZE_ASC: 
/*  937 */       long low = Long.parseLong(cursor.getSortValue());
/*  938 */       long high = cursor.getEndSortValue() != null ? Long.parseLong(cursor.getEndSortValue()) : -1L;
/*  939 */       DbSearchConstraints.Leaf top = getTopLeafConstraint();
/*  940 */       if (calcOffset) {
/*  941 */         offsetConstraints = top.clone();
/*  942 */         offsetConstraints.addSizeRange(-1L, false, low, false, true);
/*      */       }
/*  944 */       top.addSizeRange(low, true, high, false, true);
/*  945 */       break;
/*      */     
/*      */     case SIZE_DESC: 
/*  948 */       long high = Long.parseLong(cursor.getSortValue());
/*  949 */       long low = cursor.getEndSortValue() != null ? Long.parseLong(cursor.getEndSortValue()) : -1L;
/*  950 */       DbSearchConstraints.Leaf top = getTopLeafConstraint();
/*  951 */       if (calcOffset) {
/*  952 */         offsetConstraints = top.clone();
/*  953 */         offsetConstraints.addSizeRange(high, false, -1L, false, true);
/*      */       }
/*  955 */       top.addSizeRange(low, false, high, true, true);
/*  956 */       break;
/*      */     
/*      */     case SUBJ_ASC: 
/*      */     case NAME_ASC: 
/*      */     case ATTACHMENT_ASC: 
/*      */     case FLAG_ASC: 
/*      */     case PRIORITY_ASC: 
/*  963 */       String low = cursor.getSortValue();
/*  964 */       String high = cursor.getEndSortValue();
/*  965 */       DbSearchConstraints.Leaf top = getTopLeafConstraint();
/*  966 */       if (calcOffset) {
/*  967 */         offsetConstraints = top.clone();
/*  968 */         offsetConstraints.setCursorRange(null, false, low, false, sort);
/*      */       }
/*  970 */       top.setCursorRange(low, true, high, false, sort);
/*  971 */       break;
/*      */     
/*      */     case SUBJ_DESC: 
/*      */     case NAME_DESC: 
/*      */     case ATTACHMENT_DESC: 
/*      */     case FLAG_DESC: 
/*      */     case PRIORITY_DESC: 
/*  978 */       String high = cursor.getSortValue();
/*  979 */       String low = cursor.getEndSortValue();
/*  980 */       DbSearchConstraints.Leaf top = getTopLeafConstraint();
/*  981 */       if (calcOffset) {
/*  982 */         offsetConstraints = top.clone();
/*  983 */         offsetConstraints.setCursorRange(high, false, null, false, sort);
/*      */       }
/*  985 */       top.setCursorRange(low, false, high, true, sort);
/*  986 */       break;
/*      */     }
/*      */     
/*      */     
/*      */ 
/*      */ 
/*  992 */     if (offsetConstraints != null) {
/*  993 */       assert (this.cursorOffset < 0) : this.cursorOffset;
/*  994 */       Mailbox mbox = this.context.getMailbox();
/*  995 */       DbPool.DbConnection conn = DbPool.getConnection(mbox);
/*      */       try {
/*  997 */         this.cursorOffset = new DbSearch(mbox, this.context.getParams().inDumpster()).countResults(conn, offsetConstraints);
/*      */       } finally {
/*  999 */         conn.closeQuietly();
/*      */       }
/*      */     }
/*      */   }
/*      */   
/*      */   QueryOperation optimize(Mailbox mbox)
/*      */   {
/* 1006 */     return this;
/*      */   }
/*      */   
/*      */   String toQueryString()
/*      */   {
/* 1011 */     StringBuilder out = new StringBuilder("(");
/* 1012 */     if (this.luceneOp != null) {
/* 1013 */       out.append(this.luceneOp.toQueryString()).append(" AND ");
/*      */     }
/* 1015 */     this.constraints.toQueryString(out);
/* 1016 */     return ')';
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   public boolean isSearchForNonexistentLocalTag(Mailbox mbox)
/*      */   {
/* 1025 */     if ((this.allResultsQuery) || (this.includeIsRemoteFolders) || (this.luceneOp != null)) {
/* 1026 */       return false;
/*      */     }
/* 1028 */     if ((this.constraints instanceof DbSearchConstraints.Intersection)) {
/* 1029 */       DbSearchConstraints.Intersection intersection = (DbSearchConstraints.Intersection)this.constraints;
/* 1030 */       for (DbSearchConstraints child : intersection.getChildren()) {
/* 1031 */         if ((child instanceof DbSearchConstraints.Leaf)) {
/* 1032 */           DbSearchConstraints.Leaf leaf = (DbSearchConstraints.Leaf)child;
/* 1033 */           for (Tag tag : leaf.tags) {
/*      */             try {
/* 1035 */               mbox.getTagByName(null, tag.getName());
/*      */             } catch (MailServiceException mse) {
/* 1037 */               if ("mail.NO_SUCH_TAG".equals(mse.getCode())) {
/* 1038 */                 return true;
/*      */               }
/*      */             }
/*      */             catch (ServiceException e) {}
/*      */           }
/*      */         }
/*      */       }
/*      */     }
/* 1046 */     return false;
/*      */   }
/*      */   
/*      */ 
/*      */   public String toString()
/*      */   {
/* 1052 */     boolean atFirst = true;
/* 1053 */     StringBuilder result = new StringBuilder("<");
/* 1054 */     if (this.luceneOp != null) {
/* 1055 */       result.append(this.luceneOp.toString());
/* 1056 */       atFirst = false;
/*      */     }
/* 1058 */     if (!atFirst) {
/* 1059 */       result.append(" AND ");
/*      */     }
/* 1061 */     result.append("DB[");
/* 1062 */     if (this.allResultsQuery) {
/* 1063 */       result.append("ANYWHERE");
/* 1064 */     } else if (hasNoResults()) {
/* 1065 */       result.append("--- NO RESULT ---");
/*      */     } else {
/* 1067 */       if (this.includeIsLocalFolders) {
/* 1068 */         result.append("(IS:LOCAL)");
/* 1069 */       } else if (this.includeIsRemoteFolders) {
/* 1070 */         result.append("(IS:REMOTE)");
/*      */       }
/* 1072 */       result.append(this.constraints.toString());
/*      */     }
/* 1074 */     result.append("]>");
/* 1075 */     return result.toString();
/*      */   }
/*      */   
/*      */   private DBQueryOperation cloneInternal() {
/* 1079 */     assert (this.dbHits == null);
/* 1080 */     assert (this.dbHitsIter == null);
/* 1081 */     assert (this.luceneChunk == null);
/*      */     
/* 1083 */     DBQueryOperation result = (DBQueryOperation)super.clone();
/* 1084 */     result.constraints = ((DbSearchConstraints)this.constraints.clone());
/* 1085 */     result.excludeTypes.addAll(this.excludeTypes);
/* 1086 */     result.nextHits = new ArrayList();
/* 1087 */     return result;
/*      */   }
/*      */   
/*      */   public Object clone()
/*      */   {
/* 1092 */     DBQueryOperation toRet = cloneInternal();
/* 1093 */     if (this.luceneOp != null) {
/* 1094 */       toRet.luceneOp = ((LuceneQueryOperation)this.luceneOp.clone(this));
/*      */     }
/* 1096 */     return toRet;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   protected Object clone(LuceneQueryOperation caller)
/*      */   {
/* 1105 */     DBQueryOperation toRet = cloneInternal();
/* 1106 */     toRet.luceneOp = caller;
/* 1107 */     return toRet;
/*      */   }
/*      */   
/*      */   protected QueryOperation combineOps(QueryOperation other, boolean union)
/*      */   {
/* 1112 */     if (union) {
/* 1113 */       if (hasNoResults())
/*      */       {
/* 1115 */         return other;
/*      */       }
/* 1117 */       if (other.hasNoResults()) {
/* 1118 */         return this;
/*      */       }
/*      */       
/* 1121 */       if ((other instanceof DBQueryOperation)) {
/* 1122 */         DBQueryOperation dbOther = (DBQueryOperation)other;
/*      */         
/* 1124 */         if ((this.queryTarget != null) && (dbOther.queryTarget != null) && 
/* 1125 */           (!this.queryTarget.equals(dbOther.queryTarget))) {
/* 1126 */           return null;
/*      */         }
/*      */         
/* 1129 */         if (this.allResultsQuery) {
/* 1130 */           return this;
/*      */         }
/* 1132 */         dbOther = (DBQueryOperation)other;
/*      */         
/* 1134 */         if (dbOther.allResultsQuery) {
/* 1135 */           return dbOther;
/*      */         }
/* 1137 */         if ((this.luceneOp != null) || (dbOther.luceneOp != null))
/*      */         {
/* 1139 */           return null;
/*      */         }
/*      */         
/* 1142 */         if (this.queryTarget == null) {
/* 1143 */           this.queryTarget = dbOther.queryTarget;
/*      */         }
/* 1145 */         this.constraints = this.constraints.or(dbOther.constraints);
/* 1146 */         return this;
/*      */       }
/* 1148 */       return null;
/*      */     }
/*      */     
/* 1151 */     if (this.allResultsQuery) {
/* 1152 */       assert (this.luceneOp == null);
/* 1153 */       if (hasSpamTrashSetting()) {
/* 1154 */         other.forceHasSpamTrashSetting();
/*      */       }
/* 1156 */       return other;
/*      */     }
/*      */     
/* 1159 */     DBQueryOperation dbOther = null;
/*      */     
/* 1161 */     if ((other instanceof DBQueryOperation)) {
/* 1162 */       dbOther = (DBQueryOperation)other;
/*      */     } else {
/* 1164 */       return null;
/*      */     }
/*      */     
/* 1167 */     if (dbOther.allResultsQuery) {
/* 1168 */       if (dbOther.hasSpamTrashSetting()) {
/* 1169 */         forceHasSpamTrashSetting();
/*      */       }
/* 1171 */       return this;
/*      */     }
/*      */     
/* 1174 */     if ((this.queryTarget != QueryTarget.UNSPECIFIED) && (dbOther.queryTarget != QueryTarget.UNSPECIFIED) && 
/* 1175 */       (!this.queryTarget.equals(dbOther.queryTarget))) {
/* 1176 */       ZimbraLog.search.debug("ANDing two DBOps with different targets -- this is a no results query!");
/* 1177 */       return new NoResultsQueryOperation();
/*      */     }
/*      */     
/*      */ 
/* 1181 */     if (this.queryTarget == QueryTarget.UNSPECIFIED) {
/* 1182 */       this.queryTarget = dbOther.queryTarget;
/*      */     }
/* 1184 */     if (this.luceneOp != null) {
/* 1185 */       if (dbOther.luceneOp != null) {
/* 1186 */         this.luceneOp.combineOps(dbOther.luceneOp, false);
/*      */       }
/*      */     } else {
/* 1189 */       this.luceneOp = dbOther.luceneOp;
/*      */     }
/*      */     
/* 1192 */     if ((this.allResultsQuery) && (dbOther.allResultsQuery)) {
/* 1193 */       this.allResultsQuery = true;
/*      */     } else {
/* 1195 */       this.allResultsQuery = false;
/*      */     }
/*      */     
/* 1198 */     this.constraints = this.constraints.and(dbOther.constraints);
/*      */     
/* 1200 */     return this;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public List<QueryInfo> getResultInfo()
/*      */   {
/* 1207 */     List<QueryInfo> toRet = new ArrayList();
/* 1208 */     toRet.addAll(this.queryInfo);
/* 1209 */     if (this.luceneOp != null) {
/* 1210 */       toRet.addAll(this.luceneOp.getQueryInfo());
/*      */     }
/* 1212 */     return toRet;
/*      */   }
/*      */   
/*      */   protected void depthFirstRecurse(QueryOperation.RecurseCallback cb)
/*      */   {
/* 1217 */     if (this.luceneOp != null) {
/* 1218 */       this.luceneOp.depthFirstRecurseInternal(cb);
/*      */     }
/* 1220 */     cb.recurseCallback(this);
/*      */   }
/*      */   
/*      */   int getDbHitCount() throws ServiceException {
/* 1224 */     if (this.dbHitCount < 0) {
/* 1225 */       Mailbox mbox = this.context.getMailbox();
/* 1226 */       DbPool.DbConnection conn = DbPool.getConnection(mbox);
/*      */       try {
/* 1228 */         this.dbHitCount = new DbSearch(mbox, this.context.getParams().inDumpster()).countResults(conn, this.constraints);
/*      */       } finally {
/* 1230 */         conn.closeQuietly();
/*      */       }
/*      */     }
/* 1233 */     return this.dbHitCount;
/*      */   }
/*      */   
/*      */   public long getCursorOffset()
/*      */   {
/* 1238 */     return this.cursorOffset;
/*      */   }
/*      */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/index/DBQueryOperation.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */